#ifndef MTL_EXCEPTION_HPP
#define MTL_EXCEPTION_HPP

extern "C" {
#include <errno.h>
#include <string.h>
}
#include <stdexcept>
#include <sstream>
//#include <system_error>

#define PTHREAD_VALIDATE(call, msg) { \
    const int err = (call); \
    if (err != 0) { \
      throw mtl::system_error(mtl::error_code(err, mtl::system_category()), (msg)); \
    } \
  }

namespace mtl {

  enum errc {
    invalid_argument = EINVAL,
    resource_deadlock_would_occur = EDEADLK,
    no_such_process = ESRCH,
  };

  class error_category;
  class error_code;
  class error_condition;

  class error_category {
  public:
    virtual ~error_category() {}
    virtual error_condition default_error_condition(int ev) const;
    virtual std::string name() const = 0;
    virtual std::string message(int value) const = 0;
  };

  const error_category& generic_category();

  const error_category& system_category();

  class error_code {
  public:
    error_code()
      : m_value(0), m_category(&generic_category())
    {}

    error_code(const int value, const error_category& cat)
      : m_value(value), m_category(&cat)
    {}

    int value() const { return m_value; }

    const error_category& category() const { return *m_category; }

    error_condition default_error_condition() const;

    std::string message() const {
      return category().message(value());
    }

    // on C++0x, explicit operator bool() const;
    typedef void (*safe_bool_type)();
    static void safe_bool_type_true() {}
    operator safe_bool_type() const { // equals "operator bool() const"
      return value() != 0 ? safe_bool_type_true : NULL;
    }

  private:
    int             m_value;
    const error_category* m_category; // clear/assign のため pointer
  };

  class error_condition {
  public:
    error_condition(int value, const error_category& cat)
      : m_value(value), m_category(&cat)
    {}

    int value() const { return m_value; }

    const error_category& category() const { return *m_category; }

    std::string message() const {
      return category().message(value());
    }

    // on C++0x, explicit operator bool() const;
    typedef void (*safe_bool_type)();
    static void safe_bool_type_true() {}
    operator safe_bool_type() const { // equals "operator bool() const"
      return value() != 0 ? safe_bool_type_true : NULL;
    }

  private:
    int             m_value;
    const error_category* m_category; // clear/assign のため pointer
  };

  class system_error : public std::runtime_error {
  public:
    system_error(const error_code& code, const std::string& what)
      : std::runtime_error(make_message(what, code)), m_code(code)
    {}

    virtual ~system_error() throw() {}

    const error_code& code() const throw() { return m_code; }

  protected:
    static std::string make_message(const std::string& what, const error_code& code) {
      std::ostringstream ss;
      ss << what;
      if (code) {
        ss << ": " << code.message();
      }
      return ss.str();
    }
  private:
    error_code  m_code;
  };

}
#endif
